package autohotkeyide;

import autohotkeyide.autocompletion.AutoCompletionManager;
import autohotkeyide.hightlighter.Highlighter;
import com.ciklum.robotester.gui.MainPanel;
import com.gooddies.exceptions.ErrorMessageException;
import com.gooddies.persistence.Properties;
import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.HeadlessException;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.filechooser.FileFilter;

import jsyntaxpane.DefaultSyntaxKit;
import org.apache.commons.io.FileUtils;

/**
 * @author sad
 */
public class MainWindow extends JpWindow {

    private final IDETextField text;
    private File fileToSave;
    private AutoCompletionManager autocomplete;
    private Highlighter hightlighter;
     private int dif = 0;
    private String contentText;

    public MainWindow() throws HeadlessException {
        DefaultSyntaxKit.initKit();
        setTitle("Autohotkey IDE");
        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        text = new IDETextField();
//        JScrollPane scrollPane = new JScrollPane(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
//        scrollPane.getViewport().add(text);
//        add(scrollPane);
//        setJMenuBar(createMainMenu());
//        initAutoComplete();
//        initHightlighter();
        add(new MainPanel());
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                tryExit();
            }
        });
//        text.clearModified();
    }

    public void rehightlight() {
        hightlighter.paintAll();
    }

    public AutoCompletionManager getAutocompleteManager() {
        return autocomplete;
    }

    private void tryExit() {
        Properties.get().saveProperties();
        if (canCloseDocument()) {
            System.exit(0);
        }
    }

    private boolean canCloseDocument() {
        if (text.isModified()) {
            int result = JOptionPane.showConfirmDialog(this, "The document was changed, save it?", "Saving", JOptionPane.YES_NO_CANCEL_OPTION);
            if (result == JOptionPane.CANCEL_OPTION) {
                return false;
            }
            if (result == JOptionPane.YES_OPTION) {
                return save();
            }
        }
        return true;
    }

    final public JMenuBar createMainMenu() {

        JMenuBar bar = new JMenuBar();
        JMenu fileMenu = new JMenu("File");
        bar.add(fileMenu);

        JMenuItem newItem = new JMenuItem("New");
        fileMenu.add(newItem);
        newItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                newFile();
            }
        });
        fileMenu.addSeparator();
        JMenuItem openItem = new JMenuItem("Open");
        fileMenu.add(openItem);
        openItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                open();
            }
        });
        JMenuItem saveItem = new JMenuItem("Save");
        fileMenu.add(saveItem);
        saveItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                save();
            }
        });
        JMenuItem saveAsItem = new JMenuItem("Save As...");
        fileMenu.add(saveAsItem);
        saveAsItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                saveAs();
            }
        });
        fileMenu.addSeparator();
        JMenuItem exitItem = new JMenuItem("Exit");
        exitItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                tryExit();
            }
        });

        fileMenu.add(exitItem);
        JMenu snapshotMenu = new JMenu("Snapshot");
        bar.add(snapshotMenu);

        JMenu runMenu = new JMenu("Run");
        bar.add(runMenu);

        JMenuItem runMenuItem = new JMenuItem("Run");
        runMenu.add(runMenuItem);
        runMenuItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                run();
            }
        });

        JMenuItem click = new JMenuItem("FindPictureAndClick");
        snapshotMenu.add(click);
        click.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                findControlAndClick();
            }
        });

        JMenuItem move = new JMenuItem("FindPictureAndMove");
        snapshotMenu.add(move);
        move.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                findControlAndMove();
            }
        });

        JMenuItem ifFindImage = new JMenuItem("IfFindImage");
        snapshotMenu.add(ifFindImage);
        ifFindImage.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                existsOnScreen();
            }
        });

        JMenuItem WaitForImage = new JMenuItem("WaitForImage");
        snapshotMenu.add(WaitForImage);
        WaitForImage.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                WaitForImage();
            }
        });

        return bar;
    }

    private void newFile() {
        if (canCloseDocument()) {
            text.removeAllText();
            fileToSave = null;
        }
    }

    private void open() {
        if (canCloseDocument()) {
            JFileChooser chooser = new JFileChooser();
            chooser.setFileFilter(getAHKFileFilter());
            int result = chooser.showOpenDialog(this);
            if (result != JFileChooser.APPROVE_OPTION) {
                return;
            }
            fileToSave = chooser.getSelectedFile();
            Settings.imageDirectory = fileToSave.getParent() + "\\";
            String content = "";
            try {
                content = FileUtils.readFileToString(fileToSave);
            } catch (IOException ex) {
                Logger.getLogger(MainWindow.class.getName()).log(Level.SEVERE, null, ex);
            }
            text.removeAllText();
            text.insertText(0, content);
            text.clearModified();
            rehightlight();
        }
    }

    private FileFilter getAHKFileFilter() {
        return new FileFilter() {
            @Override
            public boolean accept(File f) {
                return f.getAbsolutePath().toLowerCase().endsWith(".ahk") || f.isDirectory();
            }

            @Override
            public String getDescription() {
                return "AHK files(*.ahk)";
            }
        };
    }

    private boolean saveAs() {
        JFileChooser chooser = new JFileChooser();
        chooser.setFileFilter(getAHKFileFilter());
        int result = chooser.showSaveDialog(this);
        if (result != JFileChooser.APPROVE_OPTION) {
            return false;
        }
        String lastImagePath = Settings.imageDirectory;
        fileToSave = chooser.getSelectedFile();
        String newPath = fileToSave.getParent() + "\\";

        resaveImages(lastImagePath, newPath);

        Settings.imageDirectory = fileToSave.getParent();
        saveString(fileToSave, text.getText());
        Settings.imageDirectory = newPath;
        return true;
    }

    private void saveString(File file, String text) {
        try (PrintWriter writer = new PrintWriter(file)) {
            String[] strs = text.split("\\r?\\n");

            for (String line : strs) {
                line = line.replaceAll("\\r", "");
                writer.print(line);
                writer.print(System.getProperty("line.separator"));
            }
            writer.close();
            this.text.clearModified();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(MainWindow.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    private String deleteInString(String text, int start, int length) {
        String firstPart = text.substring(0, start);
        String endPart = text.substring(start + length);
        return firstPart + endPart;
    }

    private String addInString(String text, int start, String toAdd) {
        String firstPart = text.substring(0, start);
        String endPart = text.substring(start);
        return firstPart + toAdd + endPart;
    }

    private void resaveImages(final String lastPath, final String newPath) {
        RegExpImageFinder finder = new RegExpImageFinder();
        final int differenceInPathLength = newPath.length() - lastPath.length();
        dif = 0;
        contentText = text.getText();
        text.removeAllText();
        finder.setOnFindEvent(new RegExpImageFinder.FindEvent() {
            @Override
            public void onFind(Matcher match) {
                String findedPath = match.group(1);
                int start = match.start(1);
                int length = match.end(1) - match.start(1);
                contentText = deleteInString(contentText, start + dif, length);
                //.removeText(start + dif, length);

                SelectedRegion region = SelectedRegion.load(new File(findedPath));
                String newImgPath = com.gooddies.utils.FileUtils.replacePath(findedPath, lastPath, newPath);
                String newImagePath = new File(newPath, region.getImage()).getAbsolutePath();
                try {
                    FileUtils.moveFile(new File(findedPath), new File(newImgPath));
                    FileUtils.moveFile(region.calculateImagePath(), new File(newImagePath));
                } catch (IOException ex) {
                    Logger.getLogger(MainWindow.class.getName()).log(Level.SEVERE, null, ex);
                }
                contentText = addInString(contentText, start + dif, newImgPath);
                //text.insertText(start + dif, newImagePath);
                dif += differenceInPathLength;
            }
        });

        finder.trySearch(contentText);
        text.setDisableReplacingImages(false);
        text.insertText(0, contentText);
    }

    private boolean save() {
        if (fileToSave == null) {
            return saveAs();
        } else {
            saveString(fileToSave, text.getText());
        }
        return true;
    }

    private String getInterpreterPath() {
        String path = Properties.get().getString("interprPath");
        if (path == null) {
            path = Settings.defaultAhkInterpreterDirectory;
            Properties.get().putString("interprPath", path);
        }

        return path;
    }

    private boolean checkAHKInterpreterPath() {
        File interpreter = new File(getInterpreterPath());
        if (interpreter.exists() && interpreter.canExecute()) {
            return true;
        }
        JOptionPane.showMessageDialog(this, "Autohotkey interpreter is not found. Please choose it from file system.");
        JFileChooser chooser = new JFileChooser();
        chooser.setFileFilter(new FileFilter() {
            @Override
            public boolean accept(File f) {
                if (f.isDirectory()) {
                    return true;
                }
                String toLower = f.getAbsolutePath().toLowerCase();
                return toLower.contains("autohotkey.exe");
            }

            @Override
            public String getDescription() {
                return "autohotkey.exe";
            }
        });
        int result = chooser.showOpenDialog(this);
        if (result == JFileChooser.APPROVE_OPTION) {
            File file = chooser.getSelectedFile();
            Properties.get().putString("interprPath", file.getAbsolutePath());
        }

        return false;
    }

    private void run() {
        Interpreter interpreter = new Interpreter();
        interpreter.execute(text.getText());
//try {

        /*setExtendedState(Frame.ICONIFIED);
         String lib = Utils.readResourceToString("libSearchImage.ahk");
         String toSave = lib + System.getProperty("line.separator") + text.getText();
         String fileName = Settings.imageDirectory + "tempFile.ahk";
         saveString(new File(fileName), toSave);
         Process p = Runtime.getRuntime().exec("\""+Properties.get().getString("interprPath") + "\" \"" + fileName + "\"");*/
        /* } catch (IOException ex) {
         Logger.getLogger(MainWindow.class.getName()).log(Level.SEVERE, null, ex);
         }*/
    }

    public String createSnapShot() {
        String value = null;
        SelectedRegion region = makeSelectionOnScreen();
        if (region != null) {
            String path = region.getImage();
            value = String.format("\"%s\"", path);
        }
        return value;
    }

    private void createSnapshotFunction(String functionName) {
        String snapShot = createSnapShot();
        if (snapShot == null) {
            return;
        }
        String functionInvocation = String.format(functionName, snapShot);
        text.replaceSelection(functionInvocation);
    }

    private void findControlAndClick() {
        createSnapshotFunction("findControlAndClick(%s)");
    }

    private void findControlAndMove() {
        createSnapshotFunction("findControlAndMove(%s)");
    }

    private void existsOnScreen() {
        createSnapshotFunction("existsOnScreen(%s)");
    }

    private void WaitForImage() {
        createSnapshotFunction("waitForImage(%s)");
    }

    private String saveImageAsPNG(BufferedImage image) {
        String fileName = "" + (int) (Math.random() * 9999999) + ".png";
        String filePath = Settings.imageDirectory + fileName;
        try {
            ImageIO.write(image, "png", new File(filePath));
        } catch (IOException ex) {
            Logger.getLogger(MainWindow.class.getName()).log(Level.SEVERE, null, ex);
        }

        return filePath;
    }

    private File saveImgFile(File pathToImage, Point hotSpot) {
        String fileExtension = com.gooddies.utils.FileUtils.getFileExtension(pathToImage);
        String fileName = pathToImage.getName();
        String fileNameWithoutExtension = fileName.substring(0, fileName.length() - fileExtension.length() - 1);
        java.util.Properties property = new java.util.Properties();
        property.setProperty("imagePath", fileName);
        property.setProperty("dx", "" + (int) hotSpot.getX());
        property.setProperty("dy", "" + (int) hotSpot.getY());
        File imgFile = new File(pathToImage.getParent(), fileNameWithoutExtension + ".img");
        try {
            property.store(new FileOutputStream(imgFile), null);
        } catch (IOException ex) {
            throw new ErrorMessageException("Cannot write file");
        }
        return imgFile;
    }

    private SelectedRegion makeSelectionOnScreen() {
        setVisible(false);

        try {
            Thread.sleep(500);
        } catch (InterruptedException ex) {
            Logger.getLogger(MainWindow.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            BufferedImage background = null;
            try {
                Robot robot = new Robot();
                Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
                background = robot.createScreenCapture(new Rectangle(0, 0, (int) screenSize.getWidth(), (int) screenSize.getHeight()));
            } catch (AWTException ex) {
                Logger.getLogger(MainWindow.class.getName()).log(Level.SEVERE, null, ex);
            }

            SelectionWindow window = new SelectionWindow(MainWindow.this);
            window.setBackground(background);
            SelectionWindow.SelectionResult result = window.selectRegion();
            if (result != null) {
                String fileName = saveImageAsPNG(result.selected);
                Point hotSpot = result.hotspot;
                File imgFile = saveImgFile(new File(fileName), hotSpot);
                SelectedRegion region = new SelectedRegion(imgFile.getAbsolutePath(), hotSpot, imgFile);
                return region;
            }
        } finally {
            setVisible(true);
        }
        return null;
    }

    private void initAutoComplete() {
        autocomplete = new AutoCompletionManager(text);
    }

    private void initHightlighter() {
        hightlighter = new Highlighter(text, autocomplete);
    }

    @Override
    public String getWindowName() {
        return "Main_window";
    }
}
